home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / biz / ccard11 / ccard.c < prev    next >
C/C++ Source or Header  |  1995-01-28  |  6KB  |  255 lines

  1. /*
  2.  *    ccard - credit card number validation
  3.  *    1994 Peter Miller
  4.  *    Public Domain
  5.  *
  6.  *    This program is distributed in the hope that it will be useful,
  7.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9.  *
  10.  * MANIFEST: functions to validate credit card numbers
  11.  *
  12.  * derived from code by
  13.  *    Chris Stone <cstone@hms.com>
  14.  *    The High Mountain Software Internet Gateway
  15.  *
  16.  * translated to C by
  17.  *    Peter Miller, 28-Oct-94
  18.  *    This source is hereby placed in the Public Domain.
  19.  *    Please leave my name on it,
  20.  *    and document changes in this header block.
  21.  *
  22.  * NO WARRANTY
  23.  *
  24.  *    BECAUSE THE PROGRAM IS IN THE PUBLIC DOMAIN, THERE IS NO
  25.  *    WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
  26.  *    LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE AUTHORS
  27.  *    AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
  28.  *    WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  29.  *    BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  30.  *    AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO
  31.  *    THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD
  32.  *    THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
  33.  *    NECESSARY SERVICING, REPAIR OR CORRECTION.
  34.  *
  35.  *    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
  36.  *    WRITING WILL ANY AUTHOR, OR ANY OTHER PARTY WHO MAY MODIFY
  37.  *    AND/OR REDISTRIBUTE THE PROGRAM, BE LIABLE TO YOU FOR DAMAGES,
  38.  *    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
  39.  *    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
  40.  *    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
  41.  *    RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
  42.  *    OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  43.  *    PROGRAMS), EVEN IF SUCH AUTHOR OR OTHER PARTY HAS BEEN ADVISED
  44.  *    OF THE POSSIBILITY OF SUCH DAMAGES.
  45.  */
  46.  
  47. #include <ctype.h>
  48. #include <ac/string.h>
  49.  
  50. #include <ccard.h>
  51.  
  52. #define SIZEOF(a) (sizeof(a) / sizeof((a)[0]))
  53. #define ENDOF(a) ((a) + SIZEOF(a))
  54.  
  55. #define MINLEN 12
  56. #define MAXLEN (MINLEN + 16)
  57. #define L(n) (1 << ((n) - MINLEN))
  58.  
  59.  
  60. char *
  61. ccard_type_name(n)
  62.     ccard_type_ty    n;
  63. {
  64.     static char    *name[] =
  65.     {
  66.         "unknown",
  67.         "Mastercard",
  68.         "Visa",
  69.         "American Express",
  70.         "Diners Club/Carte Blanche",
  71.         "Discover",
  72.         "enRoute",
  73.         "Japanese Credit Bureau",
  74.         "Australian Bankcard",
  75.     };
  76.  
  77.     if (n < 0 || n >= SIZEOF(name))
  78.         n = 0;
  79.     return name[n];
  80. }
  81.  
  82.  
  83. char *
  84. ccard_error_name(n)
  85.     ccard_error_ty    n;
  86. {
  87.     static char    *name[] =
  88.     {
  89.         "no error",
  90.         "card type unknown",
  91.         "card number contains non numeric characters",
  92.         "card number is far too long",
  93.         "card number is the wrong length",
  94.         "checksum incorrect",
  95.     };
  96.  
  97.     if (n < 0 || n >= SIZEOF(name))
  98.         return "unknown";
  99.     return name[n];
  100. }
  101.  
  102.  
  103. static int verify_checksum _((char *));
  104.  
  105. static int
  106. verify_checksum(credit_card)
  107.     char        *credit_card;
  108. {
  109.     char        *cp;
  110.     int        dbl;
  111.     int        check_sum;
  112.  
  113.     /*
  114.      * This checksum algorithm has a name,
  115.      * but I can't think of it.
  116.      */
  117.     check_sum = 0;
  118.     dbl = 0;
  119.     /* assert(credit_card[0]); */
  120.     cp = credit_card + strlen(credit_card) - 1;
  121.     while (cp >= credit_card)
  122.     {
  123.         int        c;
  124.  
  125.         c = *cp-- - '0';
  126.         if (dbl)
  127.         {
  128.             c *= 2;
  129.             if (c >= 10)
  130.                 c -= 9;
  131.         }
  132.         check_sum += c;
  133.         dbl = !dbl;
  134.     }
  135.  
  136.     return ((check_sum % 10) == 0);
  137. }
  138.  
  139.  
  140. static int all_numeric _((char *, char *, int));
  141.  
  142. static int
  143. all_numeric(s1, s2, max)
  144.     char    *s1;
  145.     char    *s2;
  146.     int    max;
  147. {
  148.     while (*s1)
  149.     {
  150.         if (isspace(*s1) || *s1 == '-')
  151.         {
  152.             ++s1;
  153.             continue;
  154.         }
  155.         if (!isdigit(*s1))
  156.             return ccard_error_non_numeric;
  157.         if (max <= 0)
  158.             return ccard_error_too_long;
  159.         *s2++ = *s1++;
  160.         --max;
  161.     }
  162.     *s2 = 0;
  163.     return ccard_error_none;
  164. }
  165.  
  166.  
  167. ccard_error_ty
  168. ccard_valid(credit_card_in, card_type)
  169.     char        *credit_card_in;
  170.     ccard_type_ty    *card_type;
  171. {
  172.     typedef struct table_ty table_ty;
  173.     struct table_ty
  174.     {
  175.         char        *prefix;
  176.         int        length_mask;
  177.         ccard_type_ty    type;
  178.         int        checksum;
  179.     };
  180.  
  181.     static table_ty table[] =
  182.     {
  183.         { "1800", L(15), ccard_type_jcb, 1, },
  184.         { "2014", L(15), ccard_type_enroute, 0, },
  185.         { "2131", L(15), ccard_type_jcb, 1, },
  186.         { "2149", L(15), ccard_type_enroute, 0, },
  187.         { "300",  L(14), ccard_type_diners, 1, },
  188.         { "301",  L(14), ccard_type_diners, 1, },
  189.         { "302",  L(14), ccard_type_diners, 1, },
  190.         { "303",  L(14), ccard_type_diners, 1, },
  191.         { "304",  L(14), ccard_type_diners, 1, },
  192.         { "305",  L(14), ccard_type_diners, 1, },
  193.         { "34",   L(15), ccard_type_amex, 1, },
  194.         { "36",   L(14), ccard_type_diners, 1, },
  195.         { "37",   L(15), ccard_type_amex, 1, },
  196.         { "38",   L(14), ccard_type_diners, 1, },
  197.         { "3",    L(16), ccard_type_jcb, 1, },
  198.         { "4",    L(13)|L(16), ccard_type_visa, 1, },
  199.         { "51",   L(16), ccard_type_mastercard, 1, },
  200.         { "52",   L(16), ccard_type_mastercard, 1, },
  201.         { "53",   L(16), ccard_type_mastercard, 1, },
  202.         { "54",   L(16), ccard_type_mastercard, 1, },
  203.         { "55",   L(16), ccard_type_mastercard, 1, },
  204.         { "56",   L(16), ccard_type_bankcard, 1, },
  205.         { "6011", L(16), ccard_type_discover, 1, },
  206.     };
  207.     table_ty    *tp;
  208.     char        credit_card[MAXLEN + 1];
  209.     ccard_error_ty    err;
  210.     int        len;
  211.  
  212.     /*
  213.      * copy the number, eliding spaces
  214.      * defer any errors until after we have tried to guess the card type
  215.      */
  216.     err = all_numeric(credit_card_in, credit_card, MAXLEN);
  217.  
  218.     /*
  219.      * look for the card prefix in the table
  220.      * to determine the card type
  221.      */
  222.     for (tp = table; tp < ENDOF(table); ++tp)
  223.     {
  224.         if (!memcmp(tp->prefix, credit_card, strlen(tp->prefix)))
  225.             break;
  226.     }
  227.     if (tp >= ENDOF(table))
  228.     {
  229.         *card_type = ccard_type_unknown;
  230.         return ccard_error_type_unknown;
  231.     }
  232.     *card_type = tp->type;
  233.     if (err != ccard_error_none)
  234.         return err;
  235.  
  236.     /*
  237.      * set the card type, then check the length
  238.      */
  239.     /* assert(tp->correct_length <= MAXLEN); */
  240.     len = strlen(credit_card);
  241.     if (len < MINLEN || (L(len) & tp->length_mask) == 0)
  242.         return ccard_error_length_incorrect;
  243.  
  244.     /*
  245.      * checksum
  246.      */
  247.     if (tp->checksum && !verify_checksum(credit_card))
  248.         return ccard_error_checksum;
  249.     
  250.     /*
  251.      * no errors found
  252.      */
  253.     return ccard_error_none;
  254. }
  255.